﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;

namespace MyLibrary.Text.Match
{
    /// <summary>
    /// 实现最常见的文字配备方法
    /// </summary>
    public class MatchText
    {
        #region 最常见的正则表达式
        public const string REGEX_ONLYNUMBER = "[0-9]";
        public const string REGEX_ONLYZEROORNOZEROBEGIN = "(0|[1-9][0-9]*)";
        public const string REGEX_ONLYCHINESE = "[\u4e00-\u9fa5]";
        public const string REGEX_SPECIALCHAR = "[~!@#$%^&*()_-=+{}[]|<>,.?]{1,}";
        #endregion

        #region 正则替换方法
        /// <summary>
        /// 将字符串中所有的中文字符替换成指定的分隔符,并将结果以数组的形式返回
        /// </summary>
        /// <param name="input">输入字符串</param>
        /// <param name="replacer">分隔符</param>
        /// <returns>分隔后字符串数组</returns>
        public static string[] ReplaceChinese(string input, string replacer)
        {
            Regex regex = new Regex(REGEX_ONLYCHINESE, RegexOptions.Multiline | RegexOptions.IgnoreCase);
            string normalString = regex.Replace(input, replacer).ToLower();
            string[] str = normalString.Split(new string[] { replacer }, StringSplitOptions.RemoveEmptyEntries);
            return str;
        }
        /// <summary>
        /// 替换指定正则表达式的值
        /// </summary>
        /// <param name="input">输入字符串</param>
        /// <param name="regex">正则表达式</param>
        /// <param name="replacer">替换位</param>
        /// <returns>替换后的字符串</returns>
        public static string Replace(string input, string regex, string replacer)
        {
            string result = "`-=[];',~@#$%&*(){}:<>?";
            Regex regexExpress = new Regex(regex, RegexOptions.IgnoreCase | RegexOptions.Multiline);
            string normalString = regexExpress.Replace(input, replacer);
            return normalString.ToLower();

        }
        #endregion

        #region 字符串比对方法
        /// <summary>
        /// 使用正则表达式进行匹配
        /// </summary>
        /// <param name="source">要匹配的字符串</param>
        /// <param name="regex">正则表达式</param>
        /// <returns>是否匹配</returns>
        public static bool Match(string source, string regex, out MatchCollection collection)
        {
            if (String.IsNullOrEmpty(source)) throw new ArgumentNullException("比较源为空");
            if (String.IsNullOrEmpty(regex)) throw new ArgumentNullException("正则表达式不能为空");

            Regex regexExpress = new Regex(regex, RegexOptions.IgnoreCase | RegexOptions.Multiline);
            collection = regexExpress.Matches(source);
            if (collection.Count == 0)
                return false;
            else
                return true;
        }
        /// <summary>
        /// 判断字符串是否相同
        /// </summary>
        /// <param name="source">源字符串</param>
        /// <param name="target">目标字符串</param>
        /// <returns>比对的结果</returns>
        public static bool Equal(string source, string target)
        {
            if (String.IsNullOrEmpty(source)) throw new ArgumentNullException("比较源为空");
            if (String.IsNullOrEmpty(target)) throw new ArgumentNullException("比较目标为空");
            if (source.Length != target.Length) return false;
            return source.Equals(target);

        }
        /// <summary>
        /// 实现字符串相似度算法:Levenshtein Distance 
        /// </summary>
        /// <param name="s">源字符串</param>
        /// <param name="t">目标字符串</param>
        /// <returns>相识度</returns>
        /// <remarks>
        ///  LD算法用来得到两个字符串的差距,比如CAT和KATE的距离是2.
        ///  LD算法可以看作动态规划. 它的思路就是从两个字符串的左边开
        ///  始比较,记录已经比较过的子串相似度(实际上叫做距离),然后进一步得到下一个字符位置时的相似度. 例子: GUMBO和
        ///  GAMBOL. 当算到矩阵D[3,3]位置时,也就是当比较到GUM和GAM时,要从已经比较过的3对子串GU-GAM, GUM-GA和GU-GA之中选一个差别最小的来当它的值. 所以要从左上到右下构造矩阵
        /// </remarks>
        public static double Similar(string source, string target)
        {
            int srcLength = source.Length;
            int tarLength = target.Length;
            char srcChar;
            char tarChar;
            int i;
            int j;
            int[,] matrix;
            int cost;
            //Step1;
            if (srcLength == 0) return 0.0;
            if (tarLength == 0) return 0.0;
            //Step2
            matrix = new int[tarLength + 1, srcLength + 1];
            for (i = 0; i <= srcLength; i++)
                matrix[0, i] = i;
            for (j = 0; j <= tarLength; j++)
                matrix[j, 0] = j;

            //Step3
            for (i = 1; i <= srcLength; i++)
            {
                srcChar = source[i - 1];
                //Step4
                for (j = 1; j <= tarLength; j++)
                {
                    tarChar = target[j - 1];
                    //Step5
                    if (srcChar == tarChar)
                        cost = 0;
                    else
                        cost = 1;
                    //Step6
                    matrix[j, i] = Minimum(matrix[j, i - 1] + 1, matrix[j - 1, i] + 1, matrix[j - 1, i - 1] + cost);
                }
            }
            int result = matrix[tarLength, srcLength];
            int len = srcLength > tarLength ? srcLength : tarLength;
            return 1 - ((double)result / len);
        }

        /// <summary>
        /// 获取三个数中的最小值
        /// </summary>
        private static int Minimum(int a, int b, int c)
        {
            int min;
            min = a;
            if (b < min)
                min = b;
            if (c < min)
                min = c;
            return min;
        }
        #endregion

        #region 全半角转换
        /// <summary>
        /// 转半角的函数
        /// </summary>
        /// <param name="input">输入的字符串</param>
        /// <returns>转化完成的字符串</returns>
        ///<remarks>
        ///全角空格为12288，半角空格为32
        ///其他字符半角(33-126)与全角(65281-65374)的对应关系是：均相差65248
        ///</remarks>
        public static string ToDBC(string input)
        {
            string normalinput = TurnRussianToEnglish(input.ToLower());
            normalinput = TurnGreekToEnglish(normalinput);
            char[] inputchar = normalinput.ToCharArray();
            for (int i = 0; i < inputchar.Length; i++)
            {
                if (inputchar[i] == 12288)
                    inputchar[i] = (char)32;
                else if (inputchar[i] > 65280 && inputchar[i] < 65375)
                    inputchar[i] = (char)(inputchar[i] - 65248);
            }
            return new string(inputchar);
        }
        /// <summary>
        /// 转半角的函数
        /// </summary>
        /// <param name="input">输入的字符串</param>
        /// <param name="otherFilter">特殊字符过滤</param>
        /// <returns>转化完成的字符串</returns>
        ///<remarks>
        ///全角空格为12288，半角空格为32
        ///其他字符半角(33-126)与全角(65281-65374)的对应关系是：均相差65248
        ///</remarks>
        public static string ToDBC(string input, Dictionary<int, int> otherFilter)
        {
            string normalinput = TurnRussianToEnglish(input.ToLower());
            normalinput = TurnGreekToEnglish(normalinput);
            char[] inputchar = normalinput.ToCharArray();
            for (int i = 0; i < inputchar.Length; i++)
            {
                if (inputchar[i] == 12288)
                    inputchar[i] = (char)32;
                else if (inputchar[i] > 65280 && inputchar[i] < 65375)
                    inputchar[i] = (char)(inputchar[i] - 65248);
                else if (otherFilter.ContainsKey((int)inputchar[i]))
                    inputchar[i] = (char)otherFilter[(int)inputchar[i]];
            }
            return new string(inputchar);
        }
        /// <summary>
        /// 转全角的函数
        /// </summary>
        /// <param name="input">输入的字符串</param>
        /// <returns>转化完成的字符串</returns>
        ///<remarks>
        ///全角空格为12288，半角空格为32
        ///其他字符半角(33-126)与全角(65281-65374)的对应关系是：均相差65248
        ///</remarks>
        public static string ToSBC(string input)
        {
            char[] inputchar = input.ToCharArray();
            for (int i = 0; i < inputchar.Length; i++)
            {
                if (inputchar[i] == 32)
                    inputchar[i] = (char)12288;
                else if (inputchar[i] > 32 && inputchar[i] < 127)
                    inputchar[i] = (char)(inputchar[i] + 65248);
            }
            return new string(inputchar);
        }
        #endregion

        #region 不同语言间的转换
        /// <summary>
        /// 将俄文字符转化为类似的英文字符
        /// </summary>
        /// <param name="input">输入字符串</param>
        /// <returns>过滤后的字符串</returns>
        private static string TurnRussianToEnglish(string input)
        {
            char[] inputs = input.ToCharArray();
            int length = inputs.Length;
            for (int i = 0; i < length; i++)
            {
                if (inputs[i] == 1072) inputs[i] = 'a';
                else if (inputs[i] == 1073) inputs[i] = '6';
                else if (inputs[i] == 1074) inputs[i] = 'b';
                else if (inputs[i] == 1075) inputs[i] = 'r';
                else if (inputs[i] == 1076) inputs[i] = 'n';
                else if (inputs[i] == 1077) inputs[i] = 'e';
                else if (inputs[i] == 1105) inputs[i] = 'e';
                else if (inputs[i] == 1078) inputs[i] = 'x';
                else if (inputs[i] == 1079) inputs[i] = '3';
                else if (inputs[i] == 1080) inputs[i] = 'n';
                else if (inputs[i] == 1081) inputs[i] = 'n';
                else if (inputs[i] == 1082) inputs[i] = 'k';
                else if (inputs[i] == 1083) inputs[i] = 'n';
                else if (inputs[i] == 1084) inputs[i] = 'm';
                else if (inputs[i] == 1085) inputs[i] = 'h';
                else if (inputs[i] == 1086) inputs[i] = 'o';
                else if (inputs[i] == 1087) inputs[i] = 'n';
                else if (inputs[i] == 1088) inputs[i] = 'p';
                else if (inputs[i] == 1089) inputs[i] = 'c';
                else if (inputs[i] == 1090) inputs[i] = 't';
                else if (inputs[i] == 1091) inputs[i] = 'y';
                else if (inputs[i] == 1092) inputs[i] = '中';
                else if (inputs[i] == 1093) inputs[i] = 'x';
                else if (inputs[i] == 1094) inputs[i] = 'u';
                else if (inputs[i] == 1095) inputs[i] = 'u';
                else if (inputs[i] == 1096) inputs[i] = 'w';
                else if (inputs[i] == 1097) inputs[i] = 'w';
                else if (inputs[i] == 1098) inputs[i] = 'b';
                else if (inputs[i] == 1099) inputs[i] = 'b';
                else if (inputs[i] == 1100) inputs[i] = 'b';
                else if (inputs[i] == 1101) inputs[i] = '3';
                else if (inputs[i] == 1102) inputs[i] = 'p';
                else if (inputs[i] == 1103) inputs[i] = 'r';
            }
            return new string(inputs);
        }

        /// <summary>
        /// 将希腊文字转换成类似的文字
        /// </summary>
        private static string TurnGreekToEnglish(string input)
        {
            char[] inputs = input.ToCharArray();
            int length = inputs.Length;
            for (int i = 0; i < length; i++)
            {
                if (inputs[i] == 'α') inputs[i] = 'a';
                else if (inputs[i] == 'β') inputs[i] = 'b';
                else if (inputs[i] == 'γ') inputs[i] = 'y';
                else if (inputs[i] == 'δ') inputs[i] = '6';
                else if (inputs[i] == 'ε') inputs[i] = 'e';
                else if (inputs[i] == 'ζ') inputs[i] = '3';
                else if (inputs[i] == 'η') inputs[i] = 'n';
                else if (inputs[i] == 'θ') inputs[i] = '日';
                else if (inputs[i] == 'ι') inputs[i] = 'l';
                else if (inputs[i] == 'κ') inputs[i] = 'k';
                else if (inputs[i] == 'λ') inputs[i] = '入';
                else if (inputs[i] == 'μ') inputs[i] = 'u';
                else if (inputs[i] == 'ν') inputs[i] = 'v';
                else if (inputs[i] == 'ξ') inputs[i] = 'e';
                else if (inputs[i] == 'ο') inputs[i] = 'o';
                else if (inputs[i] == 'π') inputs[i] = 'n';
                else if (inputs[i] == 'ρ') inputs[i] = 'p';
                else if (inputs[i] == 'σ') inputs[i] = 'o';
                else if (inputs[i] == 'τ') inputs[i] = 't';
                else if (inputs[i] == 'υ') inputs[i] = 'u';
                else if (inputs[i] == 'φ') inputs[i] = 'w';
                else if (inputs[i] == 'χ') inputs[i] = 'x';
                else if (inputs[i] == 'ψ') inputs[i] = 'w';
                else if (inputs[i] == 'ω') inputs[i] = 'w';
                else if (inputs[i] == 'Α') inputs[i] = 'a';
                else if (inputs[i] == 'Β') inputs[i] = 'b';
                else if (inputs[i] == 'Γ') inputs[i] = 'l';
                else if (inputs[i] == 'Δ') inputs[i] = 'a';
                else if (inputs[i] == 'Ε') inputs[i] = 'e';
                else if (inputs[i] == 'Ζ') inputs[i] = 'z';
                else if (inputs[i] == 'Η') inputs[i] = 'h';
                else if (inputs[i] == 'Θ') inputs[i] = '日';
                else if (inputs[i] == 'Ι') inputs[i] = 'i';
                else if (inputs[i] == 'Κ') inputs[i] = 'k';
                else if (inputs[i] == 'Λ') inputs[i] = 'a';
                else if (inputs[i] == 'Μ') inputs[i] = 'm';
                else if (inputs[i] == 'Ν') inputs[i] = 'n';
                else if (inputs[i] == 'Ξ') inputs[i] = '三';
                else if (inputs[i] == 'Ο') inputs[i] = 'o';
                else if (inputs[i] == 'Π') inputs[i] = 'n';
                else if (inputs[i] == 'Ρ') inputs[i] = 'p';
                else if (inputs[i] == 'Σ') inputs[i] = 'e';
                else if (inputs[i] == 'Τ') inputs[i] = 't';
                else if (inputs[i] == 'Υ') inputs[i] = 'y';
                else if (inputs[i] == 'Φ') inputs[i] = '中';
                else if (inputs[i] == 'Χ') inputs[i] = 'x';
                else if (inputs[i] == 'Ψ') inputs[i] = 'w';
                else if (inputs[i] == 'Ω') inputs[i] = 'n';
            }
            return new string(inputs);
        }
        #endregion
    }
}
